using System.Collections;
namespace Slaks.Graphs.Wordnet
{
	public class WordnetGraph : Graph
	{
		public WordnetGraph() : base()
		{
		}

		public WordnetGraph(string name) : base(name)
		{
		}

		/// <summary>
		/// Create the vertex with specified id. <br>
		/// If the vertex already exists then return this vertex otherwise create new, add to graph and return  the vertex
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public new WordnetVertex CreateAddVertex(long id)
		{
			WordnetVertex vertex = GetVertex(id);
			if (vertex != null) return vertex;
			vertex = new WordnetVertex(id);
			m_id2VertexMapper.Add(vertex.GetId(), vertex);
			m_vertexList.Add(vertex);
			return vertex;
		}

		public WordnetVertex GetVertexWithSynonymLookUp(long id, int synonymBetweenCategory, int synonymWithinCategory)
		{
			WordnetVertex vertex = GetVertex(id);
			if (vertex != null) return vertex;

			foreach (WordnetVertex vrtx in this.m_vertexList)
			{
				if (vrtx.IsSynonymExistsUntilSpecificLevel(id, synonymBetweenCategory, synonymWithinCategory)) return vrtx;
			}

			return null;
		}

		/// <summary>
		/// Get the vertex by its id
		/// </summary>
		/// <param name="id">vertex id</param>
		/// <returns>vertex if exists and null otherwise</returns>
		public new WordnetVertex GetVertex(long id)
		{
			if (m_id2VertexMapper.Contains(id)) return (WordnetVertex) m_id2VertexMapper[id];
			return null;
		}

        public static int SynonymLevelWithinSense = 2;
        public static int SynonymLevelBetweenSense = 2;
        
        public override Graph GetMCS(Graph two)
        {
            WordnetGraph graphOne = this;
            WordnetGraph graphTwo = (WordnetGraph)two;

            WordnetGraph bigGraph;
            WordnetGraph smallGraph;
            if (graphOne.GetVertexCount() > graphTwo.GetVertexCount())
            {
                bigGraph = graphOne;
                smallGraph = graphTwo;
            }
            else
            {
                bigGraph = graphTwo;
                smallGraph = graphOne;
            }

            //one.SortVertices();
            //two.SortVertices());

            WordnetGraph commonGraph = new WordnetGraph();

            WordnetVertex commonVertex;
            WordnetVertex commonVertexNext;

            #region find vertices

            long vertexId;
            //bool isSynFound = false;
            //int synonymLevelWithinSense = 0;
            //int synonymLevelBetweenSense = 0;
            WordnetVertex tempVertex;
            foreach (WordnetVertex vertex in bigGraph.GetVertexList())
            {
                vertexId = vertex.GetId();
                tempVertex = smallGraph.GetVertexWithSynonymLookUp(vertexId, SynonymLevelBetweenSense, SynonymLevelWithinSense);
                if (tempVertex != null)
                {
                    //create node id in common graph which equals to the id of the second graph in which synonym of the
                    //vertexId was found
                    commonVertex = commonGraph.CreateAddVertex(tempVertex.GetId());
                    if (tempVertex.GetId() != vertexId && commonVertex.IsDirty == false)
                    {
                        commonVertex.IsDirty = true;
                        //assign vertexId as direct synonym id of the tempVertex
                        commonVertex.DirectSynonymId = vertexId;
                    }
                }
            } //end of foreach

            #endregion

            #region find edges

            VertexList commonVertexList = commonGraph.GetVertexList();
            if (commonVertexList.Count <= 1) return commonGraph;

            Vertex vertexBigGraph;
            Vertex vertexSmallGraph;

            Vertex vertexBigGraphNext;
            Vertex vertexSmallGraphNext;

            long commonVertexIdBigGraph = 0;
            long commonVertexIdSmallGraph = 0;

            long nextIdBigGraph;
            long nextIdSmallGraph;
            //long commonIdNext;
            IDictionary sectionsOne, sectionsTwo;

            for (int i = 0; i < commonVertexList.Count; i++)
            {
                commonVertex = (WordnetVertex)commonVertexList[i];
                if (commonVertex.IsDirty)
                {
                    commonVertexIdBigGraph = commonVertex.DirectSynonymId;
                }
                else commonVertexIdBigGraph = commonVertex.GetId();
                commonVertexIdSmallGraph = commonVertex.GetId();

                vertexBigGraph = bigGraph.GetVertex(commonVertexIdBigGraph);
                vertexSmallGraph = smallGraph.GetVertex(commonVertexIdSmallGraph);

                for (int j = i; j < commonVertexList.Count; j++)
                {
                    commonVertexNext = (WordnetVertex)commonVertexList[j];
                    if (commonVertexNext.IsDirty)
                    {
                        nextIdBigGraph = commonVertexNext.DirectSynonymId;
                    }
                    else nextIdBigGraph = commonVertexNext.GetId();

                    nextIdSmallGraph = commonVertexNext.GetId();

                    sectionsOne = vertexBigGraph.GetSectionsIfConnected(nextIdBigGraph);
                    sectionsTwo = vertexSmallGraph.GetSectionsIfConnected(nextIdSmallGraph);

                    ICollection sectionsOneKeys = sectionsOne.Keys;

                    foreach (string section in sectionsOneKeys)
                    {
                        if (sectionsTwo.Contains(section))
                        {
                            commonVertexList[i].AddEdge(commonVertexList[j], section);
                        }
                    }

                    if (commonVertexIdBigGraph == nextIdBigGraph) continue;

                    //find opposite directions
                    vertexBigGraphNext = bigGraph.GetVertex(nextIdBigGraph);
                    vertexSmallGraphNext = smallGraph.GetVertex(nextIdSmallGraph);

                    sectionsOne = vertexBigGraphNext.GetSectionsIfConnected(commonVertexIdBigGraph);
                    sectionsTwo = vertexSmallGraphNext.GetSectionsIfConnected(commonVertexIdSmallGraph);

                    sectionsOneKeys = sectionsOne.Keys;
                    foreach (string section in sectionsOneKeys)
                    {
                        if (sectionsTwo.Contains(section))
                        {
                            commonVertexList[j].AddEdge(commonVertexList[i], section);
                        }
                    }

                } //end of for
            }

            #endregion

            return commonGraph;
        }

	}
}